package com.hqb.multi_transfer.controller;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.hqb.multi_transfer.model.Transfer;
import com.hqb.multi_transfer.repository.Repository;
import com.hqb.multi_transfer.service.FileStorageService;
import com.hqb.multi_transfer.service.FileStorageService.StoredFile;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.LocalDateTime;
import java.util.Enumeration;
import java.util.List;
import java.util.Optional;


@Controller
@RequestMapping("/transfer")
public class TransferController {

    private final Repository repo;
    private final FileStorageService storage;

    public TransferController(Repository repo, FileStorageService storage) {
        this.repo = repo;
        this.storage = storage;
    }

    @GetMapping
    public String list(Model model) {
        List<Transfer> items = repo.findAll();
        model.addAttribute("items", items);
        return "transfer/list";
    }

    @GetMapping("/new")
    public String form(Model model) {
        model.addAttribute("transfer", new Transfer());
        return "transfer/form";
    }

    @PostMapping
    public String create(@RequestParam("content") String content,
                         @RequestParam(value = "file", required = false) MultipartFile file) throws IOException {
        Transfer a = new Transfer();
        a.setContent(content);
        a.setCreatedAt(LocalDateTime.now());
        if (file != null) {
            StoredFile sf = storage.store(file);
            if (sf != null) {
                a.setOriginalFilename(sf.originalFilename);
                a.setStoredFilename(sf.storedFilename);
                a.setContentType(sf.contentType);
                a.setSize(sf.size);
            }
        }
        repo.save(a);
        return "redirect:/transfer";
    }

    @GetMapping("/{id}/delete")
    public String delete(@PathVariable Long id) {
        repo.deleteById(id);
        return "redirect:/transfer";
    }

    @GetMapping("/{id}")
    public String view(@PathVariable Long id, Model model) {
        Optional<Transfer> oa = repo.findById(id);
        if (oa.isEmpty()) return "redirect:/transfer";
        model.addAttribute("transfer", oa.get());
        return "transfer/view";
    }

    @GetMapping("/{id}/download")
    public ResponseEntity<?> download(@PathVariable Long id) throws IOException {
        Optional<Transfer> oa = repo.findById(id);
        if (oa.isEmpty()) return ResponseEntity.notFound().build();
        Transfer a = oa.get();
        if (a.getStoredFilename() == null) return ResponseEntity.badRequest().body("no file");

        Path p = storage.load(a.getStoredFilename());
        if (p == null) return ResponseEntity.notFound().build();

        InputStreamResource resource = new InputStreamResource(Files.newInputStream(p));

        String contentType = a.getContentType() != null ? a.getContentType() : MediaType.APPLICATION_OCTET_STREAM_VALUE;

        return ResponseEntity.ok()
                .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + a.getOriginalFilename() + "\"")
                .contentLength(a.getSize() != null ? a.getSize() : Files.size(p))
                .contentType(MediaType.parseMediaType(contentType))
                .body(resource);
    }

    @GetMapping("/qrcode")
    @ResponseBody
    public ResponseEntity<byte[]> generateQRCode(@RequestHeader(value = "Host", required = false) String hostHeader) {
        try {
            // 获取服务器地址
            String serverUrl;
//            if (hostHeader != null && !hostHeader.isEmpty()) {
//                serverUrl = "http://" + hostHeader + "/transfer";
//            } else {
//                try {
//                    // 获取局域网IP地址
//                    String localIP = getLocalIPAddress();
//                    // 默认端口为8080
//                    serverUrl = "http://" + localIP + ":8080/transfer";
//                } catch (Exception e) {
//                    serverUrl = "http://localhost:8080/transfer";
//                }
//            }


            try {
                // 获取局域网IP地址
                String localIP = getLocalIPAddress();
                // 默认端口为8080
                serverUrl = "http://" + localIP + ":8080/transfer";
            } catch (Exception e) {
                serverUrl = "http://localhost:8080/transfer";
            }

            // 生成二维码
            QRCodeWriter qrCodeWriter = new QRCodeWriter();
            BitMatrix bitMatrix = qrCodeWriter.encode(serverUrl, BarcodeFormat.QR_CODE, 200, 200);

            ByteArrayOutputStream pngOutputStream = new ByteArrayOutputStream();
            MatrixToImageWriter.writeToStream(bitMatrix, "PNG", pngOutputStream);

            return ResponseEntity.ok()
                    .contentType(MediaType.IMAGE_PNG)
                    .body(pngOutputStream.toByteArray());
        } catch (WriterException | IOException e) {
            return ResponseEntity.status(500).body(null);
        }
    }

    /**
     * 获取本机局域网IP地址
     *
     * @return 局域网IP地址
     * @throws SocketException 网络异常
     */
    private String getLocalIPAddress() throws SocketException {
        Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
        while (interfaces.hasMoreElements()) {
            NetworkInterface networkInterface = interfaces.nextElement();
            // 排除回环接口和未运行的接口
            if (networkInterface.isLoopback() || !networkInterface.isUp()) {
                continue;
            }

            Enumeration<InetAddress> addresses = networkInterface.getInetAddresses();
            while (addresses.hasMoreElements()) {
                InetAddress address = addresses.nextElement();
                // 排除回环地址和IPv6地址
                if (address.isLoopbackAddress() || address instanceof Inet6Address) {
                    continue;
                }

                // 检查是否为IPv4私有地址
                String ipAddress = address.getHostAddress();
                if (isPrivateAddress(ipAddress)) {
                    return ipAddress;
                }
            }
        }
        // 如果没有找到私有地址，返回第一个有效的IPv4地址
        interfaces = NetworkInterface.getNetworkInterfaces();
        while (interfaces.hasMoreElements()) {
            NetworkInterface networkInterface = interfaces.nextElement();
            if (networkInterface.isLoopback() || !networkInterface.isUp()) {
                continue;
            }

            Enumeration<InetAddress> addresses = networkInterface.getInetAddresses();
            while (addresses.hasMoreElements()) {
                InetAddress address = addresses.nextElement();
                if (address.isLoopbackAddress() || address instanceof Inet6Address) {
                    continue;
                }

                return address.getHostAddress();
            }
        }
        // 如果仍然没有找到，返回localhost
        return "127.0.0.1";
    }

    /**
     * 判断是否为私有地址
     *
     * @param ipAddress IP地址
     * @return 是否为私有地址
     */
    private boolean isPrivateAddress(String ipAddress) {
        // 10.x.x.x
        if (ipAddress.startsWith("10.")) {
            return true;
        }
        // 172.16.x.x - 172.31.x.x
        if (ipAddress.startsWith("172.")) {
            String[] parts = ipAddress.split("\\.");
            if (parts.length > 1) {
                int secondPart = Integer.parseInt(parts[1]);
                return secondPart >= 16 && secondPart <= 31;
            }
        }
        // 192.168.x.x
        if (ipAddress.startsWith("192.168.")) {
            return true;
        }
        return false;
    }
}